// FUNDP 2011-2012 - Syntaxe et Sémantique
// Projet Compilateur LSD12
// Groupe 12
// -Magnette Loic
// -Lazard Alexandre
// -Oleksandrow Nicolas  
// -Turchetti Anthony


/* compilo.y
 */

%{
#include <stdio.h>
#include <stdlib.h>

#include "ast.h"
#include "syntaxvalidator.h"
#include "pcode.h"
#include "trace.h"
#include "symTree.h"

extern int num_lines;
extern char* yytext;

  
// to avoid 'implicit definition'
int yylex(void);
int yyerror(char *str);

ASTTREE root;
%}


// définition du type des variables $x
%union{
        int ival;
        char *sval;
        int bval;
        ASTTREE tval;
}

//TOKEN definition
%token PROG FUNC FORWARD
%token IF THEN ELSE FI
%token WHILE DO OD
%token ADD TO
%token REMOVE FROM
%token TAG_BEGIN TAG_END
%token RETURN
%token READ WRITE ASSIGN
%token EOL SEMI_COL
%token VAR
%token AND OR
%token NOT
%token EQUALS LE LT IN
%token PLUS MINUS 
%token MULTIPLY DIVIDE
%token MIN MAX SHARP
%token LP COMMA RP

// token des valeurs de variables
%token <sval> ID
%token <bval> BOOL
%token <ival> NB 
%token <ival> TYPE

//precedence order: { && , || } < { ! } < {=,<=,<,in} < {+,-} < {*,/} < {min,max,#} < { (.)}
%left AND OR
%left NOT
%left EQUALS LE LT IN
%left PLUS MINUS 
%left MULTIPLY DIVIDE
%left MIN MAX SHARP

// token des types
%type <tval> InstructionList Instruction RExpr DeclareVar DefineVar Id Implementation Function 
%type <tval> Function_body Function_header Program Args_Definition Args_Parameter IfBody


%start Program

%%


Program :PROG Id EOL Function TAG_END EOL
                { root = createNode(AT_PROG, AT_UNKNOWN, 0, NULL, UNDIF_BOOL, $2, $4);}
;

Function :      Function_header Function_body { $$ = createNode(AT_FUNC, AT_UNKNOWN, 0, NULL,UNDIF_BOOL,$1,$2);}
            |   Function_header FORWARD EOL { $$ = createNode(AT_FUNC, AT_UNKNOWN, 0, NULL,UNDIF_BOOL,$1,NULL);}
;

Function_header : FUNC Id LP Args_Definition RP SEMI_COL TYPE EOL
                { $$ = createNode(AT_FUNC_HEAD, $7, 0, NULL, UNDIF_BOOL, $4, $2);}
;


Function_body : DeclareVar Implementation 
                { $$ = createNode(AT_FUNC_BODY, AT_UNKNOWN, 0, NULL, UNDIF_BOOL, $1, $2);}
;


Args_Definition :                               { $$ = NULL; }
                | Id SEMI_COL TYPE                       {  $$ = createArgumentDefNode(AT_ARGS, $3, FALSE, $1 , NULL);}
                | Id SEMI_COL TYPE COMMA Args_Definition {  $$ = createArgumentDefNode(AT_ARGS, $3, FALSE, $1 , $5);}
				| VAR Id SEMI_COL TYPE  {  $$ = createArgumentDefNode(AT_ARGS, $4, TRUE, $2 , NULL);}
				| VAR Id SEMI_COL TYPE COMMA Args_Definition {  $$ = createArgumentDefNode(AT_ARGS, $4, TRUE, $2 , $6);}
				
;

Args_Parameter:                             { $$ = NULL; }
                | RExpr                        { $$ = createNode(AT_ARGS, AT_UNKNOWN, 0, NULL,UNDIF_BOOL, $1 , NULL);}
                | RExpr COMMA Args_Parameter   { $$ = createNode(AT_ARGS, AT_UNKNOWN, 0, NULL,UNDIF_BOOL, $1 , $3);}
;


DeclareVar : VAR DefineVar { $$ = createNode(AT_DECLARE_BLOC, AT_UNKNOWN, 0, NULL, UNDIF_BOOL, $2, NULL);}
            |VAR { $$ = createNode(AT_DECLARE_BLOC, AT_UNKNOWN, 0, NULL,UNDIF_BOOL, NULL , NULL);}
;


DefineVar :  Id TYPE EOL DefineVar  { $$ = createNode(AT_DECLARE, $2, 0, NULL,UNDIF_BOOL, $4 , $1);}
            |Id TYPE EOL            { $$ = createNode(AT_DECLARE, $2, 0, NULL,UNDIF_BOOL, NULL , $1);}
            | Function              { $$ = createNode(AT_DECLARE, AT_FUNC, 0, NULL,UNDIF_BOOL, NULL , $1);}
            | Function DefineVar    { $$ = createNode(AT_DECLARE, AT_FUNC, 0, NULL,UNDIF_BOOL, $2 , $1);}
;



Implementation : TAG_BEGIN InstructionList TAG_END EOL
                                    { $$ = createNode(AT_IMPL, AT_UNKNOWN, 0, NULL ,UNDIF_BOOL,$2, NULL);}
;

InstructionList :                             
                                        { $$ = NULL; }
                | InstructionList Instruction 
                                        { $$ = createNode(AT_ILIST,AT_UNKNOWN, 0, NULL,UNDIF_BOOL, $1, $2);}
;


Instruction :
             Id ASSIGN RExpr EOL                            {$$ = createNode(AT_OPASS,AT_UNKNOWN, 0, NULL,UNDIF_BOOL, $1, $3);}
			| WRITE RExpr EOL                               {$$ = createNode(AT_OPWRITE,AT_UNKNOWN, 0, NULL,UNDIF_BOOL, $2, NULL);}
            | READ  RExpr EOL                               {$$ = createNode(AT_OPREAD,AT_UNKNOWN, 0, NULL,UNDIF_BOOL, $2, NULL);}
            | RETURN RExpr EOL                              {$$ = createNode(AT_RETURN, AT_UNKNOWN, 0, NULL, UNDIF_BOOL, $2, NULL);}
            | RExpr EOL                                     {$$ = $1;}
            | IF LP RExpr RP THEN IfBody FI EOL             {$$ = createNode(AT_IF,AT_BOOL, 0, NULL, UNDIF_BOOL, $3,$6);} 
            | WHILE LP RExpr RP DO InstructionList OD EOL   {$$ = createNode(AT_WHILE, AT_BOOL, 0, NULL, UNDIF_BOOL, $3, $6);}
            | ADD RExpr TO Id                               {$$ = createNode(AT_ADD_TO, AT_BOOL, 0, NULL, UNDIF_BOOL, $2, $4);}
            | REMOVE RExpr FROM Id                          {$$ = createNode(AT_DEL_FROM, AT_BOOL, 0, NULL, UNDIF_BOOL, $2, $4);};
            | EOL                                           {$$ = NULL;};
            
;




IfBody : InstructionList                        {$$ = createNode(AT_IF_BODY,AT_UNKNOWN, 0, NULL, UNDIF_BOOL, $1, NULL);}
         |InstructionList ELSE InstructionList  {$$ = createNode(AT_IF_BODY,AT_UNKNOWN, 0, NULL, UNDIF_BOOL, $1, $3);} 
;

RExpr : NB                      {$$ = createNode(AT_NB,AT_NB, yylval.ival, NULL,UNDIF_BOOL, NULL, NULL);}
	  | RExpr PLUS RExpr        {$$ = createNode(AT_OPADD,AT_NB, 0, NULL,UNDIF_BOOL, $1, $3);} 
      | RExpr MINUS RExpr       {$$ = createNode(AT_OPSUB,AT_NB, 0, NULL,UNDIF_BOOL, $1, $3);}
      | RExpr MULTIPLY RExpr    {$$ = createNode(AT_OPMUL,AT_NB, 0, NULL,UNDIF_BOOL, $1, $3);}
      | RExpr DIVIDE RExpr      {$$ = createNode(AT_OPDIV,AT_NB, 0, NULL,UNDIF_BOOL, $1, $3);}	 
      | MINUS RExpr             {$$ = createNode(AT_NEG,AT_NB, 0, NULL, UNDIF_BOOL, NULL, $2);}
	  | Id                      {$$ = $1;}				   
	  | BOOL                    {$$ = createNode(AT_BOOL,AT_BOOL, 0, NULL,yylval.bval, NULL, NULL);} 
	  | RExpr AND RExpr         {$$ = createNode(AT_AND, AT_BOOL, 0, NULL,UNDIF_BOOL, $1, $3);}     
	  | RExpr OR RExpr          {$$ = createNode(AT_OR, AT_BOOL, 0, NULL,UNDIF_BOOL, $1, $3);} 
	  | NOT RExpr               {$$ = createNode(AT_NOT, AT_BOOL, 0, NULL,UNDIF_BOOL, NULL, $2);}  
      | RExpr EQUALS RExpr      {$$ = createNode(AT_OPEQ, AT_BOOL, 0, NULL,UNDIF_BOOL, $1, $3);}	  
 	  | RExpr LT RExpr          {$$ = createNode(AT_LT, AT_BOOL, 0, NULL,UNDIF_BOOL, $1, $3);}
	  | RExpr LE RExpr          {$$ = createNode(AT_LE, AT_BOOL, 0, NULL,UNDIF_BOOL, $1, $3);}
	  | LP RExpr RP             {$$ = $2;}
      | Id LP Args_Parameter RP {$$ = createNode(AT_FUNC_CALL, AT_UNKNOWN, 0, NULL, UNDIF_BOOL, $1, $3); }
      | SHARP Id                {$$ = createNode(AT_SHARP, AT_NB, 0, NULL,UNDIF_BOOL, $2, NULL);}
      | RExpr IN Id             {$$ = createNode(AT_IN, AT_BOOL, 0, NULL, UNDIF_BOOL, $1, $3);}

;


Id : ID { $$ = createNode(AT_ID,AT_UNKNOWN, 0, yylval.sval,UNDIF_BOOL, NULL, NULL);};



%%

int yyerror(char *str)
{
        fprintf(stderr,"KO\n");
        printf("ERROR '%s' AT LINE  %d : UNRECOGNISED '%s'\n",str,num_lines,yytext);
        exit(0);
}
int main()
{ 
  SYMTREE symTree;

  printf("; *** compiler project\n");
  printf("; *** G12 \n");
  printf(";\n");

  printf(";*** BEGIN yyparse() ***\n");
  yyparse();
  printf(";*** END yyparse() ***\n");
   
  printf(";*** BEGIN printTree(..) ***\n");   
  char* outFile_AST_XML = "myAST.xml";
  //remove existing AST XML
  remove(outFile_AST_XML);
  //Write the new AST XML
   writeToFile(outFile_AST_XML,"<root>");
   printTreeXML(root,outFile_AST_XML);
   writeToFile(outFile_AST_XML,"\n</root>");
 
  printf(";*** END printTree(..) ***\n");

  printf(";*** BEGIN SymbolTree ***\n");
  symTree = createSymTree();
  int ret = fillSymbolTree(root, symTree);
  if ( ret == -1 )
  {
    fprintf(stderr,"KO\n");
	exit(1);	//Error
  }
  printf(";*** END SymbolTree ***\n");
  printf(";*** BEGIN printSymbolTree(..) ***\n");
  printSymTree(symTree);
  printf(";*** END printSymbolTree(..) ***\n");
  
  
  printf(";*** BEGIN computeLocations(..) ***\n");
  //computeLocations(sym);
  printf(";*** END computeLocations(..) ***\n");

  printf(";*** BEGIN printSymbolTable(..) +locations ***\n");
  //TraceSym(sym);
  printf(";*** END printSymbolTable(..) +locations ***\n");
  
  printf(";*** BEGIN validation() ***\n");
  if ( validateSyntax(root,symTree) == -1)
  {
	printf("Something wrong ... \n");
    fprintf(stderr,"KO\n");
	exit(1);	//Error
  }
   printf(";*** END validation() ***\n");

  printf(";*** BEGIN PCodeGeneration ***\n");
  pcodeGenValue(root, symTree);
  printf(";*** END PCodeGeneration ***\n");
  
  printf(";*** BEGIN Cleaning ***\n");
  freeNode(root);
  freeSymTree(symTree);
  printf(";*** END Cleaning ***\n");
 
  fprintf(stderr,"OK\n");
  
  return 0;
}
